package cn.wolfcode.day02;

import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.io.IOUtils;
import org.junit.Test;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Activiti7Demo02 {
    /**************************** 昨日代码 Start ***********************************/
    // 。。。
    // 部署方法
    @Test
    public void testDeploy(){
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deploy = repositoryService.createDeployment()    // 创建部署对象
                .addClasspathResource("bpmn/leaveProcessIGateway.bpmn20.xml")   // 部署 XML 文件
                .deploy();      // 部署
    }
    // 启动流程 （形成流程实例）
    @Test
    public void testStartProcessInstance(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取运行时 RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 调用 RuntimeService 中的 API 来启动流程实例
        ProcessInstance processInstance =
                runtimeService.startProcessInstanceByKey("leaveProcess");
        System.out.println("流程实例id:" + processInstance.getId());
    }
    // 完成任务
    @Test
    public void testCompleteTask(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取任务 TaskService
        TaskService taskService = processEngine.getTaskService();
        // 任务 ID
        String taskId = "5009";
        // 完成任务
        taskService.complete(taskId);
    }
    /**************************** 昨日代码 end ***********************************/
    // 查询流程定义 （在我们当前 Activiti7 中部署了多少个流程）
    @Test
    public void testQueryProcessDefinition(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取仓库 RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 查询流程定义 XxxService.CreateXxxxQuery  RepositoryService.CreateProcessDefinitionQuery()
        // 若需要什么条件则直接添加即可。需要什么条件就添加什么条件。
        List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery()
                .list();
        for (ProcessDefinition processDefinition : processDefinitionList) {
            System.out.println("流程定义ID：" + processDefinition.getId());
            System.out.println("流程定义名称：" + processDefinition.getName());
            System.out.println("流程定义Key：" + processDefinition.getKey());
            System.out.println("流程定义Version：" + processDefinition.getVersion());
            System.out.println("流程定义对应的部署ID：" + processDefinition.getDeploymentId());
            System.out.println("♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥♥");
        }
    }

    // 流程定义删除
    @Test
    public void deleteProcessDefinition(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取仓库 RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 需要删除的流程定义对应的部署ID 10001
        String deploymentId = "15001";
        // 删除流程定义
        // 第二个参数本质上就是将数据库中的外键更新规则设置为 cascade。 默认值是 false
        repositoryService.deleteDeployment(deploymentId,true);
    }

    // 流程资源下载
    @Test
    public void testDownloadFile() throws Exception {
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取仓库 RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 查询对应的流程定义对象
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("leaveProcess")   // 根据流程定义 Key 查询
                .latestVersion()        // 最后一个版本
                .singleResult();
        // 获取 bpmn 文件名
        String bpmnFileName = processDefinition.getResourceName();
        // 获取 png 文件名
        String pngFileName = processDefinition.getDiagramResourceName();
        // 调用 Activiti 中的 API 通过名字可以获取到一个输入流（该流中就可以获取到 bpmn 文件资源）
        InputStream bpmnInputStream =
                repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), bpmnFileName);
        // 调用 Activiti 中的 API 通过名字可以获取到一个输入流（该流中就可以获取到 png 文件资源）
        InputStream pngInputStream =
                repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), pngFileName);
        // 创建 bpmn 输出流，指定输出位置和文件名
        FileOutputStream bpmnFileOutPutStream = new FileOutputStream("E:/leaveProcess.bpmn");
        // 创建 png 输出流，指定输出位置和文件名
        FileOutputStream pngFileOutPutStream = new FileOutputStream("E:/leaveProcess.png");

        // 使用 apache 的 common-io 依赖中的工具类来实现上传下载
        IOUtils.copy(bpmnInputStream,bpmnFileOutPutStream);
        IOUtils.copy(pngInputStream,pngFileOutPutStream);

        // 释放资源
        pngFileOutPutStream.close();
        bpmnFileOutPutStream.close();
        pngInputStream.close();
        bpmnInputStream.close();

    }

    // 启动流程并绑定BusinessKey
    @Test
    public void testStartProcessInstanceBindBusinessKey(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取运行时 RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 模拟插入业务表数据，返回一个业务 ID 为 8001
        String BusinessKey = "8001";
        // 调用 RuntimeService 中的 API 来启动流程实例
        ProcessInstance processInstance =
                runtimeService.startProcessInstanceByKey("leaveProcess",BusinessKey);
        System.out.println("流程实例ID：" + processInstance);
    }

    // 查询任务同时查询到 BusinessKey
    @Test
    public void testQueryTask(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取任务 TaskService
        TaskService taskService = processEngine.getTaskService();
        // 获取运行时 RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 查询指定用户的待办任务。
        String userId = "张三";
        // 查询待办任务
        List<Task> taskList = taskService.createTaskQuery()       // 这里相当于 select 语句
                .taskAssignee(userId)       // 添加条件为指定负责人
                .processDefinitionKey("leaveProcess")   // 再次添加条件要求只要该 Key 的任务。
                .list();
        // 遍历这个待办任务集合
        for(Task task : taskList){
            // 查询当前任务对应的流程实例 ID
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(task.getProcessInstanceId())
                    .singleResult();
            // 通过流程实例对象 拿到 BusinessKey
            System.out.println("BusinessKey：" + processInstance.getBusinessKey());
        }
    }

    // 挂起/激活流程定义
    @Test
    public void testSuspendProcessDefinition(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取仓库 RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 查询流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("leaveProcess")
                .latestVersion()
                .singleResult();
        // 查询当前流程定义的挂起状态  true 挂起  false 不挂起。 默认值 false
        System.out.println("当前流程定义是否被挂起：" + processDefinition.isSuspended());
        if(processDefinition.isSuspended()){
            // 挂起   我们需要激活流程定义。
            repositoryService.activateProcessDefinitionById(processDefinition.getId());
            System.out.println("该流程定义已经被激活");
        } else {
            // 没挂起  我们需要挂起流程定义。
            repositoryService.suspendProcessDefinitionById(processDefinition.getId());
            System.out.println("该流程定义已经被挂起");
        }
    }
    // 挂起/激活流程定义及实例
    @Test
    public void testSuspendProcessDefinitionAndProcessInstance(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取仓库 RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        // 查询流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey("leaveProcess")
                .latestVersion()
                .singleResult();
        // 查询当前流程定义的挂起状态  true 挂起  false 不挂起。 默认值 false
        System.out.println("当前流程定义是否被挂起：" + processDefinition.isSuspended());
        if(processDefinition.isSuspended()){
            // 挂起   我们需要激活流程定义。
            // 三个参数。 第一个激活流程定义的 ID，第二个 是否激活当前流程定义下面正在执行的流程实例， 第三个什么时间激活， null 立即激活。
            repositoryService.activateProcessDefinitionById(processDefinition.getId(),true,null);
            System.out.println("该流程定义及对应的流程实例已经被激活");
        } else {
            // 没挂起  我们需要挂起流程定义。
            // 三个参数。 第一个挂起流程定义的 ID，第二个 是否挂起当前流程定义下面正在执行的流程实例， 第三个什么时间挂起， null 立即挂起。
            repositoryService.suspendProcessDefinitionById(processDefinition.getId(),true,null);
            System.out.println("该流程定义及对应的流程实例已经被挂起");
        }
    }
    // 挂起/激活流程实例
    @Test
    public void testSuspendProcessInstance(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取运行时 RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // 流程实例 ID
        String processInstanceId = "5001";
        // 查询流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();

        // 查询当前流程定义的挂起状态  true 挂起  false 不挂起。 默认值 false
        System.out.println("当前流程实例是否被挂起：" + processInstance.isSuspended());
        if(processInstance.isSuspended()){
            // 挂起   我们需要激活流程定义。
            runtimeService.activateProcessInstanceById(processInstance.getId());
            System.out.println("该流程实例已经被激活");
        } else {
            // 没挂起  我们需要挂起流程定义。
            runtimeService.suspendProcessInstanceById(processInstance.getId());
            System.out.println("该流程实例已经被挂起");
        }
    }
    // 启动流程时绑定负责人
    @Test
    public void testStartProcessInstanceBindAssignee(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取运行时 RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // BusinessKey
        String businessKey = "8001";
        // 为负责人赋值
        Map<String,Object> variables = new HashMap<>();
        // Key 就是图中你设置的占位变量，  值就是需要设置的负责人
        // variables.put("assignee0","林大爷");
        // variables.put("assignee1","徐老师");
        variables.put("assignee0","李超楠");
        variables.put("assignee1","琳姐");
        // 启动流程
        runtimeService.startProcessInstanceByKey("leaveProcess",variables);
        // runtimeService.startProcessInstanceByKey("leaveProcess",businessKey,variables);
    }
    // 启动流程时绑定候选人
    @Test
    public void testStartProcessInstanceBindCandidate(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取运行时 RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // BusinessKey
        String businessKey = "8001";
        // 为负责人赋值
        Map<String,Object> variables = new HashMap<>();
        // Key 就是图中你设置的占位变量，  值就是需要设置的候选人
        variables.put("assignee0","徐老师");
        variables.put("assignee1","张老师");
        // 启动流程
        runtimeService.startProcessInstanceByKey("leaveProcess",variables);
        // runtimeService.startProcessInstanceByKey("leaveProcess",businessKey,variables);
    }
    // 根据任务候选人查询待办任务并认领任务
    @Test
    public void testQueryTaskByCandidateUser(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取任务 TaskService
        TaskService taskService = processEngine.getTaskService();
        // 查询指定候选人的待办任务。
        String userId = "徐老师";
        // 查询待办任务
        List<Task> taskList = taskService.createTaskQuery()       // 这里相当于 select 语句
                .taskCandidateUser(userId)       // 添加条件为候选人
                .processDefinitionKey("leaveProcess")   // 再次添加条件要求只要该 Key 的任务。
                .list();
        // 遍历这个待办任务集合
        for(Task task : taskList){
            System.out.println("任务ID：" + task.getId());
            System.out.println("任务名称：" + task.getName());
            System.out.println("任务负责人：" + task.getAssignee());
            System.out.println("任务创建时间：" + task.getCreateTime());
            System.out.println("当前任务对应的流程实例ID：" + task.getProcessInstanceId());
            System.out.println("当前任务对应的流程定义ID：" + task.getProcessDefinitionId());
        }
    }
    // 候选人认领任务
    @Test
    public void testClaim(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取任务 TaskService
        TaskService taskService = processEngine.getTaskService();
        // 候选人。
        String userId = "林大爷";
        // 任务 ID
        String taskId = "2507";
        // 认领任务
        taskService.claim(taskId,userId);
        // 完成任务
        taskService.complete(taskId);
    }
    // 完成任务
    @Test
    public void testCompleteTask1(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取任务 TaskService
        TaskService taskService = processEngine.getTaskService();
        // 任务 ID
        String taskId = "7519";
        // 完成任务
        taskService.complete(taskId);
    }
    // 启动程序绑定流程变量
    @Test
    public void testStartProcessInstanceBindVariables(){
        // 获取流程引擎对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        // 获取运行时 RuntimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        // BusinessKey
        String businessKey = "8001";
        // 流程变量赋值
        Map<String,Object> variables = new HashMap<>();
        // 负责人，节点变量
        variables.put("assignee0","部门经理张三");
        variables.put("assignee1","人事李四");
        variables.put("assignee2","总经理王五");
        variables.put("assignee4","人事助理小王");
        // 天数， 连线上面的变量， 会影响程序的走向。
        // variables.put("day","0");
        variables.put("day","4");
        // 启动流程
        runtimeService.startProcessInstanceByKey("leaveProcess",variables);
        // runtimeService.startProcessInstanceByKey("leaveProcess",businessKey,variables);
    }
}
